# -*- coding=utf-8 -*-
# library: jionlp
# author: dongrixinyu
# license: Apache License 2.0
# email: dongrixinyu.89@163.com
# github: https://github.com/dongrixinyu/JioNLP
# description: Preprocessing & Parsing tool for Chinese NLP
# website: http://www.jionlp.com


import re
import os

'------------------------------将15位身份证转成18位----------------------------------'

class ChangeIdCard():
    '''
    功能：将15位身份证转成18位
    使用：
    change = ChangeIdCard() #实例化
    result = change('152127670903003') #拿到18位的

    '''

    wi = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1, ]
    vi = [1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2, ]

    def get_verity(self,eighteen_card):
        """
        :param eighteen_card:
        :return:
        """
        ai = []
        remaining = ''
        if len(eighteen_card) == 18:
            eighteen_card = eighteen_card[0:-1]
        if len(eighteen_card) == 17:
            s = 0
        for i in eighteen_card:
            ai.append(int(i))
        for i in range(17):
            s = s + self.wi[i] * ai[i]
            remaining = s % 11
        return 'X' if remaining == 2 else str(self.vi[remaining])

    def __call__(self,fifteen_card):
        """
        15位转18位
        :param fifteen_card: 15位身份证
        :return: 18位身份证
        """
        if len(fifteen_card) != 15:
            raise ValueError('身份证号码不是15位的，无法使用')
        eighteen_card = fifteen_card[0:6] + '19' + fifteen_card[6:15]
        return eighteen_card + self.get_verity(eighteen_card)


'-------------------------------提取18位身份证号码信息------------------------------------------'

#中国： 省-市-县 各级的对应关系的文件
CHINA_LOCATION_FILE_PATH = os.path.join(os.path.dirname(__file__),'files','china_location.txt')
#解析的规则
ID_CARD_CHECK_PATTERN = r'^(1[1-5]|2[1-3]|3[1-7]|4[1-6]|5[0-4]|6[1-5]|71|81|82|91)' \
                        r'(0[0-9]|1[0-9]|2[0-9]|3[0-4]|4[0-3]|5[1-3]|90)' \
                        r'(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-3]|5[1-7]|6[1-4]|7[1-4]|8[1-7])' \
                        r'(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])\d{3}[0-9xX]$'

def china_location_loader(detail=False):
    """ 加载中国地名词典 china_location.txt

    Args:
        detail(bool): 若为 True，则返回 省、市、县区、乡镇街道、村社区 五级信息；
            若为 False，则返回 省、市、县区 三级信息

    """
    with open(CHINA_LOCATION_FILE_PATH,'r', encoding='utf-8') as f:
        location_jio = f.readlines()

    cur_province = None
    cur_city = None
    cur_county = None
    cur_town = None
    cur_village = None
    location_dict = {}

    for item in location_jio:
        if not item.startswith('\t'):  # 省
            if len(item.strip().split('\t')) != 3:
                continue

            province, admin_code, alias_name = item.strip().split('\t')
            cur_province = province
            location_dict.update(
                {cur_province: {'_full_name': province,
                                '_alias': alias_name,
                                '_admin_code': admin_code}})

        elif item.startswith('\t\t\t\t'):  # 村、社区
            if not detail:
                continue
            cur_village = item.strip()
            location_dict[cur_province][cur_city][cur_county][cur_town].update(
                {cur_village: None})

        elif item.startswith('\t\t\t'):  # 乡镇、街道
            if not detail:
                continue
            cur_town = item.strip()
            location_dict[cur_province][cur_city][cur_county].update(
                {cur_town: dict()})

        elif item.startswith('\t\t'):  # 县、区
            if len(item.strip().split('\t')) != 3:
                continue
            county, admin_code, alias_name = item.strip().split('\t')
            cur_county = county
            location_dict[cur_province][cur_city].update(
                {cur_county: {'_full_name': county,
                              '_alias': alias_name,
                              '_admin_code': admin_code}})

        else:  # 市
            if len(item.strip().split('\t')) != 3:
                continue
            city, admin_code, alias_name = item.strip().split('\t')
            cur_city = city
            location_dict[cur_province].update(
                {cur_city: {'_full_name': city,
                            '_alias': alias_name,
                            '_admin_code': admin_code}})

    return location_dict

class IDCardParser(object):
    """ 身份证号码解析器，给定一个身份证号码，解析其对应的省、市、县、出生年月、性别、校验码。

    Args:
        None

    Returns:
        dict: 身份证号解析结果字段

    Examples:
        # >>> import jionlp as jio
        # >>> text = '52010320171109002X'
        # >>> res = jio.parse_id_card(text)
        # >>> print(res)

        # {'province': '贵州省',
        #  'city': '贵阳市',
        #  'county': '云岩区',
        #  'birth_year': '2017',
        #  'birth_month': '11',
        #  'birth_day': '09',
        #  'gender': '女',
        #  'check_code': 'x'}

    """

    def __init__(self):
        self.china_locations = None
        self.id_card_check_pattern = re.compile(ID_CARD_CHECK_PATTERN)

    def _prepare(self):
        china_loc = china_location_loader()
        china_locations = dict()
        for prov in china_loc:
            if not prov.startswith('_'):
                china_locations.update(
                    {china_loc[prov]['_admin_code']:
                         [prov, None, None]})
                for city in china_loc[prov]:
                    if not city.startswith('_'):
                        china_locations.update(
                            {china_loc[prov][city]['_admin_code']:
                                 [prov, city, None]})
                        for county in china_loc[prov][city]:
                            if not county.startswith('_'):
                                china_locations.update(
                                    {china_loc[prov][city][county]['_admin_code']:
                                         [prov, city, county]})
        self.china_locations = china_locations

    def __call__(self, id_card):
        if self.china_locations is None:
            self._prepare()
        #2023-05-19，将15位身份证转成18位
        if len(id_card) == 15:
            change = ChangeIdCard()
            id_card = change(id_card)
        # 检查是否是身份证号
        match_flag = self.id_card_check_pattern.match(id_card)

        if match_flag is None:
            print('验证不通过')
            return None

        if id_card[:6] in self.china_locations.keys():
            prov, city, county = self.china_locations[id_card[:6]]
        elif id_card[:4] + '0' * 2 in self.china_locations.keys():
            prov, city, county = self.china_locations[id_card[:4] + '0' * 2]
        elif id_card[:2] + '0' * 4 in self.china_locations.keys():
            prov, city, county = self.china_locations[id_card[:2] + '0' * 4]
        else:
            # 前六位行政区划全错
            print('前六位行政区划全错')
            return None

        gender = '男' if int(id_card[-2]) % 2 else '女'
        check_code = id_card[-1]
        if check_code == 'X':
            check_code = 'x'

        return {'province': prov, 'city': city,
                'county': county,
                'birth_year': id_card[6:10],
                'birth_month': id_card[10:12],
                'birth_day': id_card[12:14],
                'gender': gender,
                'check_code': check_code}

#可以调用这个，也可以调用parser_idcard 中parser_id_car
'''
ret = parser_id_car(身份证号码)
'''
parse_id_card = IDCardParser()